import { BaseRequestConfig, BaseResponse } from './type';
import { merge } from './util';

export type HttpRequestInterceptorsItem<R> = {
    onFulfilled: (config: R) => R | Promise<R>;
    onRejected: (error: any) => any | Promise<any>;
};
export type HttpResponseInterceptorsItem<S> = {
    onFulfilled: (response: S) => any | Promise<any>;
    onRejected: (error: any) => any | Promise<any>;
};

export type HttpManagerInterceptors<R, S> = {
    request: HttpRequestInterceptorsItem<R>[];
    response: HttpResponseInterceptorsItem<S>[];
};

abstract class BaseRequest<
    KiteRequestConfig extends BaseRequestConfig = BaseRequestConfig,
    KiteResponseResult extends BaseResponse = BaseResponse
> {
    protected options: KiteRequestConfig;
    private queue: Array<{ id: string; fun: () => Promise<void> }> = []; // 请求队列
    private interceptors: HttpManagerInterceptors<KiteRequestConfig, KiteResponseResult> = {
        request: [],
        response: []
    };
    maxConcurrent: number;
    running: Set<string>;
    requestIdCounter: number;
    constructor(config?: KiteRequestConfig) {
        if (new.target === BaseRequest) {
            // 防止直接实例化抽象类
            throw new Error('Abstract class cannot be instantiated');
        }
        this.options = merge(this.getDefaultConfig(), config || ({} as KiteRequestConfig));
        this.queue = []; // 请求队列
        this.running = new Set(); // 正在执行的请求（使用唯一请求ID标识）
        this.maxConcurrent = this.options.maxConcurrent || 5;
        this.requestIdCounter = 0; // 请求ID计数器
    }
    setMaxConcurrent(max: number) {
        this.maxConcurrent = max;
    }
    generateRequestId() {
        return `req-${this.requestIdCounter++}`;
    }
    protected getDefaultConfig(): KiteRequestConfig {
        return {
            timeout: 5000,
            headers: { 'Content-Type': 'application/json' }
        } as unknown as KiteRequestConfig;
    }

    executeQueue() {
        while (this.running.size < this.maxConcurrent && this.queue.length > 0) {
            const nextItem = this.queue.shift();
            // 检查队列中的请求是否已被取消（可扩展取消逻辑）
            nextItem?.fun();
        }
    }

    request(config: KiteRequestConfig): Promise<any> {
        const requestInterceptorChain: any[] = [];
        const responseInterceptorChain: any[] = [];
        const newConfig = merge(this.options, config);
        
        if (newConfig.withRequestIntercepter && Array.isArray(this.interceptors.request) && this.interceptors.request.length) {
            this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
                requestInterceptorChain.unshift(interceptor.onFulfilled, interceptor.onRejected);
            });
        }
        if (newConfig.withResponseIntercepter && Array.isArray(this.interceptors.response) && this.interceptors.response.length) {
            this.interceptors.response.forEach(function unshiftRequestInterceptors(interceptor) {
                responseInterceptorChain.unshift(interceptor.onFulfilled, interceptor.onRejected);
            });
        }
        const chain: any[] = [this.dispatchRequest, undefined];
        Array.prototype.unshift.apply(chain, requestInterceptorChain);
        Array.prototype.push.apply(chain, responseInterceptorChain);
        const len = chain.length;
        let promise = Promise.resolve(newConfig);
        let i = 0;
        while (i < len) {
            promise = promise.then(chain[i++], chain[i++]);
        }
        const requestId = this.generateRequestId();
        return new Promise((resolve, reject) => {
            const runRequest = async () => {
                try {
                    this.running.add(requestId);
                    const response = await promise;
                    resolve(response);
                } catch (error) {
                    reject(error);
                } finally {
                    this.running.delete(requestId); // 移除对应请求ID
                    // 执行队列中的下一个请求
                    this.executeQueue();
                }
            };
            if (this.running.size < this.maxConcurrent) {
                runRequest();
            } else {
                // 加入队列（保存请求ID和执行函数）
                this.queue.push({ id: requestId, fun: runRequest });
            }
        });
    }

    protected abstract dispatchRequest(config: KiteRequestConfig): Promise<KiteResponseResult>;

    useRequestInterceptor(
        onFulfilled: (config: KiteRequestConfig) => KiteRequestConfig | Promise<KiteRequestConfig>,
        onRejected: (error: any) => any | Promise<any>
    ) {
        this.interceptors.request.push({ onFulfilled, onRejected });
        return () => {
            const index = this.interceptors.request.findIndex(
                (interceptor) =>
                    interceptor.onFulfilled === onFulfilled && interceptor.onRejected === onRejected
            );
            if (index !== -1) {
                this.interceptors.request.splice(index, 1);
            }
        };
    }
    useResponseInterceptor(
        onFulfilled: (response: KiteResponseResult) => any | Promise<any>,
        onRejected: (error: any) => any | Promise<any>
    ) {
        this.interceptors.response.push({ onFulfilled, onRejected });
        return () => {
            const index = this.interceptors.response.findIndex(
                (interceptor) =>
                    interceptor.onFulfilled === onFulfilled && interceptor.onRejected === onRejected
            );
            if (index !== -1) {
                this.interceptors.response.splice(index, 1);
            }
        };
    }
    get(url: string, config?: KiteRequestConfig): Promise<KiteResponseResult> {
        return this.request({
            ...config,
            method: 'GET',
            url
        } as KiteRequestConfig) as Promise<KiteResponseResult>;
    }

    post(url: string, params?: any, config?: KiteRequestConfig): Promise<KiteResponseResult> {
        return this.request({
            ...config,
            method: 'POST',
            params,
            url
        } as KiteRequestConfig) as Promise<KiteResponseResult>;
    }
}

export default BaseRequest;
